package com.module.bp.engine;

import java.applet.Applet;
import java.awt.Dimension;

import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLProfile;

import com.dalonedrau.awt.imagesloader.ImagesLoader;
import com.dalonedrau.jogl.engine.GameApplet;
import com.dalonedrau.jogl.engine.GameCanvas;
import com.dalonedrau.jogl.engine.GameController;
import com.dalonedrau.jogl.engine.GameDrawable;
import com.dalonedrau.jogl.engine.GameState;
import com.dalonedrau.jogl.engine.GlobalConsts;
import com.dalonedrau.jogl.engine.Interface;
import com.dalonedrau.jogl.engine.ProjectConstants;
import com.dalonedrau.jogl.opengl.AnimationsLoader;
import com.dalonedrau.jogl.opengl.TextLoader;
import com.dalonedrau.jogl.opengl.TextureLoader;
import com.dalonedrau.watchable.Watchable;
import com.dalonedrau.watchable.Watcher;
import com.jogamp.opengl.util.texture.Texture;
import com.module.bp.bus.graph.SimpleGraph;
import com.module.bp.event.base.EndPhaseEvent;
import com.module.bp.event.numbered.EventE001;
import com.module.bp.player.BPParty;
import com.module.bp.player.BPPlayer;
import com.module.bp.player.dat.Prince;

public class BPController extends GameController implements Watcher {
	/** the one and only instance of the <code>GameController</code> class. */
	private static BPController	instance;
	/**
	 * Gives access to the singleton instance of {@link GameController}.
	 * @return {@link GameController}
	 */
	public static BPController getInstance() {
		if (BPController.instance == null) {
			BPController.instance = new BPController();
			GameController.setInstance(BPController.instance);
			GameState.getInstance().addWatcher(BPController.instance);
		}
		return BPController.instance;
	}
	/** the animation library. */
	private AnimationsLoader	animationLibrary;
	/** the {@link GameCanvas} instance. */
	private GameCanvas			canvas;
	/** flag indicating the game has started. */
	private boolean				gameStarted		= false;
	/** the image library. */
	private ImagesLoader		imageLibrary;
	/** flag indicating the applet has been initialized. */
	private boolean				initAppletDone	= false;
	/** the graph for the overworld map. */
	private SimpleGraph			overworldGraph;
	/** the image library. */
	private TextureLoader		textureLibrary;
	/** Hidden constructor. */
	private BPController() {}
	/**
	 * Sets the overworldGraph.
	 * @return {@link SimpleGraph}
	 */
	public SimpleGraph getOverworldGraph() {
		return overworldGraph;
	}
	/*
	 * (non-Javadoc)
	 * @see com.dalonedrau.opengl.GameController#getTexture(java.lang.String)
	 */
	@Override
	public Texture getTexture(final int id) throws Exception {
		return textureLibrary.getTexture(id);
	}
	/** Initializes the animations library. */
	@Override
	public final void initAnimations() {
		if (animationLibrary == null) {
			try {
				animationLibrary =
						new AnimationsLoader("animations.txt",
								"com/cob/dat/images/");
			} catch (Exception ex) {
				JOGLErrorHandler.getInstance().fatalError(ex);
			}
		}
	}
	@Override
	protected void initApplet() {
		try {
			Applet a = GameApplet.getInstance();

			a.setFocusTraversalKeysEnabled(false);
			a.setFocusTraversalKeysEnabled(false);
			a.setPreferredSize(new Dimension(
					GlobalConsts.SCREEN_WIDTH,
					GlobalConsts.SCREEN_HEIGHT
					));
			a.setMinimumSize(new Dimension(
					GlobalConsts.SCREEN_WIDTH,
					GlobalConsts.SCREEN_HEIGHT
					));

			// * enable double buffering
			// GLCapabilities capabilities = new GLCapabilities(null);
			GLCapabilities capabilities =
					new GLCapabilities(GLProfile.getDefault());
			capabilities.setDoubleBuffered(true);
			canvas = new GameCanvas(
					capabilities,
					GlobalConsts.SCREEN_WIDTH,
					GlobalConsts.SCREEN_HEIGHT
					);
			a.add(canvas);
			a.setVisible(true);
			initAppletDone = true;
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	/** Initializes the texture library. */
	public final void initCursors() {
		if (imageLibrary == null) {
			try {
				imageLibrary =
						new ImagesLoader("cursors.txt",
								"com/cob/dat/images/");
				GameDrawable.setPanCursor(GameDrawable.PAN_NORTHWEST_CURSOR,
						imageLibrary.getImage("cursor_north_west"));
				GameDrawable.setPanCursor(GameDrawable.PAN_NORTH_CURSOR,
						imageLibrary.getImage("cursor_north"));
				GameDrawable.setPanCursor(GameDrawable.PAN_NORTHEAST_CURSOR,
						imageLibrary.getImage("cursor_north_east"));
				GameDrawable.setPanCursor(GameDrawable.PAN_EAST_CURSOR,
						imageLibrary.getImage("cursor_east"));
				GameDrawable.setPanCursor(GameDrawable.PAN_SOUTHEAST_CURSOR,
						imageLibrary.getImage("cursor_south_east"));
				GameDrawable.setPanCursor(GameDrawable.PAN_SOUTH_CURSOR,
						imageLibrary.getImage("cursor_south"));
				GameDrawable.setPanCursor(GameDrawable.PAN_SOUTHWEST_CURSOR,
						imageLibrary.getImage("cursor_south_west"));
				GameDrawable.setPanCursor(GameDrawable.PAN_WEST_CURSOR,
						imageLibrary.getImage("cursor_west"));
			} catch (Exception ex) {
				JOGLErrorHandler.getInstance().fatalError(ex);
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void initGameData() {
		try {
			Init.getInstance().initGameData();
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void initTextureLibrary() {
		if (textureLibrary == null) {
			try {
				textureLibrary =
						new TextureLoader("images.txt",
								"com/cob/dat/images/");
				TextLoader.getInstance().setLibraryFolder(
						"com/module/bp/dat/txt/");
			} catch (Exception ex) {
				JOGLErrorHandler.getInstance().fatalError(ex);
			}
		}
		initCursors();
	}
	/**
	 * Sets the overworldGraph.
	 * @param graph the overworldGraph to set
	 */
	public void setOverworldGraph(final SimpleGraph graph) {
		overworldGraph = graph;
	}
	/**
	 * Starts the game.
	 * @throws Exception if an error occurs
	 */
	public void startGame() throws Exception {
		Prince p = new Prince();
		BPParty.getInstance().addMember(p);
		BPPlayer.getInstance().computePlayerFullStats(p);
		Turn.getInstance().addEvent(new EventE001());
		Turn.getInstance().addEvent(new EndPhaseEvent());
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void switchScreen() throws Exception {
		if (!initAppletDone) {
			initApplet();
		}
		// load views
		ProjectConstants.getInstance().assignViews();
		switch (GameState.getInstance().getCurrentState()) {
		case GameState.STATE_01STARTMENU:
			Interface.getInstance().setCurrentView(0);
			break;
		case GameState.STATE_11LOADING:
			Interface.getInstance().setCurrentView(1);
			break;
		case GameState.STATE_12WORLD_MAP:
			Interface.getInstance().setCurrentView(2);
			break;
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void update() {
		try {
			// 1. check to see if events are done
			if (Turn.getInstance().eventsCompletedForCurrentPhase()) {
				// all events completed. just wait for input
				System.out.println("***********ALL EVENTS COMPLETED for phase "
						+ Turn.getInstance().getCurrentPhase());
			} else {
				// still have events in the current phase
				System.out.println("***********HAVE EVENTS for phase "
						+ Turn.getInstance().getCurrentPhase());
				if (Turn.getInstance().currentPhaseHasEventToFire()) {
					System.out
							.println("***********HAVE EVENT TO FIRE for phase "
									+ Turn.getInstance().getCurrentPhase());
					Turn.getInstance().fireNextEvent();
				} else {
					System.out.println("***********NO EVENT TO FIRE for phase "
							+ Turn.getInstance().getCurrentPhase());
				}
			}
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void watchUpdated(final Watchable data) {
		if (data instanceof GameState) {
			try {
				switchScreen();
			} catch (Exception ex) {
				JOGLErrorHandler.getInstance().fatalError(ex);
			}
		}
	}
}
